#ifndef __COMPILE_RUN_HPP__
#define __COMPILE_RUN_HPP__

#include <string>
#include <jsoncpp/json/json.h>

#include "./compiler.hpp"
#include "./runner.hpp"
#include "../common/asynclog.hpp"
#include "../common/situation.hpp"
#include "../common/util.hpp"

namespace yx
{
    class CompileRun
    {
    public:
        CompileRun() = default;
        ~CompileRun() = default;

        // 删除生成的临时文件
        static void removeTempFile(const std::string &file_name)
        {
            // 源文件
            std::string file_src = PathUtil::getSrc(file_name);
            if (FileUtil::isFileExist(file_src))
            {
                FileUtil::unlinkFile(file_src);
            }
            // 编译错误文件
            std::string file_compile_error = PathUtil::getCompileErr(file_name);
            if (FileUtil::isFileExist(file_compile_error))
            {
                FileUtil::unlinkFile(file_compile_error);
            }
            // 可执行程序
            std::string file_exe = PathUtil::getExe(file_name);
            if (FileUtil::isFileExist(file_exe))
            {
                FileUtil::unlinkFile(file_exe);
            }
            // 运行标准输入
            std::string file_stdin = PathUtil::getRunIn(file_name);
            if (FileUtil::isFileExist(file_stdin))
            {
                FileUtil::unlinkFile(file_stdin);
            }
            // 运行标准输出
            std::string file_stdout = PathUtil::getRunOut(file_name);
            if (FileUtil::isFileExist(file_stdout))
            {
                FileUtil::unlinkFile(file_stdout);
            }
            // 运行标准错误
            std::string file_stderr = PathUtil::getRunErr(file_name);
            if (FileUtil::isFileExist(file_stderr))
            {
                FileUtil::unlinkFile(file_stderr);
            }
        }
        // in_str:
        //      "code":
        //      "input":
        //      "cpu_limit"
        //      "mem_limit":
        // out_str:
        //      "status":
        //      "reason":
        //      "stdout":
        //      "stderr":
        static void start(const std::string &in_str, std::string &out_str)
        {
            Json::Value out_val;

            // 1. 反序列化
            Json::Value in_val;
            Json::Reader reader;
            reader.parse(in_str, in_val);

            // 2. 获取输入数据
            std::string code = in_val["code"].asString();
            std::string input = in_val["input"].asString();
            int cpu_limit = in_val["cpu_limit"].asInt();
            int mem_limit = in_val["mem_limit"].asInt();

            if (code.empty())
            {
                out_str = SubmitCodeEmpty().what();
                return;
            }

            // 3. 生成唯一源文件
            std::string file_name = FileUtil::uniqueFileName();
            if (!FileUtil::writeFile(PathUtil::getSrc(file_name), code))
            {
                out_str = InternalError().what();
                removeTempFile(file_name);

                return;
            }

            // 4.编译
            if (!Compiler::compile(file_name))
            {
                out_str = CompilationFailure(PathUtil::getCompileErr(file_name)).what();
                removeTempFile(file_name);

                return;
            }

            // 5.运行
            int ret = Runner::run(file_name, cpu_limit, mem_limit);

            if (ret>0) // 运行失败
            {
                out_str = RunFailure(ret).what();
                removeTempFile(file_name);

                return;
            }
            else if (ret<0) // 内部错误
            {
                out_str = InternalError().what();
                removeTempFile(file_name);

                return;
            }
            else // 运行成功
            {
                Json::Value val;
                Json::FastWriter writer;
                val["status"] = 0;
                val["reason"] = "运行完毕!!!";

                // 将标准输出及标准错误的信息返回
                std::string rout_str;
                FileUtil::readFile(PathUtil::getRunOut(file_name), rout_str);
                val["stdout"] = rout_str;
                std::string rerr_str;
                FileUtil::readFile(PathUtil::getRunErr(file_name), rerr_str);
                val["stderr"] = rerr_str;

                out_str = writer.write(val);
                removeTempFile(file_name);
                return;
            }
        }
    };
}

#endif // __COMPILE_RUN_HPP__